/* 

The default layout provider used by liteGrid.  This renders
a grid that supports resizable columns, a fixed header row,
and a footer. It also provides jQuery UI integration.

*/
function BasicLayoutProvider() {
	var base = this;

	//LiteGrid references that are set during initialization.
	var liteGrid = null;
	var options = null;

	//Initializes the layout, creates the header table, etc.
	base.initialize = function(grid, opt) {
		liteGrid = grid;
		options = opt;

		//This creates all the placeholder markup that might be used by other modules.

		//Create a div to wrap everything and make it jQuery UI-themable. 
		liteGrid.wrapperDiv = $("<div class='litegrid ui-widget'></div>");
		liteGrid.$el.before(liteGrid.wrapperDiv);

		//If the grid's element has an ID, use it to build the ID of the wrapper
		if (liteGrid.$el.attr("id")) {
			liteGrid.wrapperDiv.attr("id", liteGrid.$el.attr("id") + "-wrapper");
		}

		//Create placeholders, and put the original table in the body placeholder.
		liteGrid.headerDiv = $("<div class='grid-header'></div>");
		liteGrid.wrapperDiv.append(liteGrid.headerDiv);

		liteGrid.bodyDiv = $("<div class='grid-body'></div>");
		liteGrid.wrapperDiv.append(liteGrid.bodyDiv);
		liteGrid.bodyDiv.append(liteGrid.$el);

		liteGrid.footerDiv = $("<div class='gridFooter'></div>");
		liteGrid.wrapperDiv.append(liteGrid.footerDiv);

		//Create a header table.
		liteGrid.headerTable = $("<table><thead><tr></tr></thead></table>");
		liteGrid.headerDiv.append(liteGrid.headerTable);
	}

	//(Re-)Renders the table from the specified dataset.
	base.render = function(dataSet) {

		//Clear any existing table markup
		liteGrid.$el.empty();
		$("tr", liteGrid.headerTable).empty();
		$("colgroup", liteGrid.headerTable).remove();

		//Build the header and column definitions.
		var headerRow = $("tr", liteGrid.headerTable);
		var headerColgroup = $("<colgroup></colgroup>").prependTo(liteGrid.headerTable);

		//The data table needs matching column definitions
		var colgroup = $("<colgroup></colgroup>").appendTo(liteGrid.$el);

		$(options.columns).each(function() {
			//IE safety check.  If someone accidentally ended the column array with a comma, there will be a
			//null element.
			if (this == null)
				return;

			var headerCell = $("<th/>").addClass("ui-widget-header");
			var richHeader = $("<div/>").addClass(this.field + "RichHeader").html(this.header || this.field);
			headerRow.append(headerCell.append(richHeader));

			var headerCol = $("<col/>").addClass(this.field + "Column");
			var bodyCol = headerCol.clone();
			headerColgroup.append(headerCol);
			colgroup.append(bodyCol);

			//Make the header resizable.
			richHeader.resizable(
			{
				handles: "e",
				resize: function(event, ui) {
					bodyCol.width(ui.element.width());
					headerCol.width(ui.element.width());
				}
			});
		});

		//This is a placeholder that will expand to fill the remaining space automagically.
		headerColgroup.append($("<col class='filler-column' />"));
		colgroup.append($("<col class='filler-column' />"));

		//IE requires that we add a dummy placeholder to both tables.  The other cell
		//is added post-render.
		headerRow.append($("<th class='filler-cell'></th>"));

		//When the body is scrolled, we want to scroll the header as well
		liteGrid.bodyDiv.scroll(function(event) {
			//liteGrid.headerDiv.scrollLeft($(this).scrollLeft());
			var left = -1 * $(this).scrollLeft();
			liteGrid.headerTable.css("margin-left", left);
		});

		liteGrid.$el.trigger("headerRendered", liteGrid);

		//Add the rows to the table.
		base.renderRows(dataSet.dataItems);

		//The table has been rendered, so trigger the event.
		liteGrid.$el.trigger("tableUpdated", liteGrid);

		//Rendering complete.
		liteGrid.$el.trigger("tableRendered");
	}
	
	//Renders the specified items into the table.
	base.renderRows = function(dataItems) {

		if (!dataItems) {
			console.warn("No data items available to render.");
			return;
		}

		$(dataItems).each(function() {
			var row = base.buildRow(this);

			liteGrid.$el.append(row);
		});
	}
	
	//Builds a row that can be inserted into the table.
	base.buildRow = function(dataItem) {

		var row = $("<tr></tr>");

		//Add cells for everything.
		$(options.columns).each(function() {
			row.append("<td></td>");
		});

		//Add the filler cell
		$("<td class='filler-cell'></td>").appendTo(row);

		base.bindRow(row, dataItem);

		return row;
	}

	//(Re-)Binds a row to the specified data item. All existing data in the row is overwritten.
	base.bindRow = function(row, dataItem) {

		var rowId = dataItem[options.rowIdColumn];

		//If the row already has an ID, see if we're changing the ID.
		if (row.attr("id") != undefined && row.attr("id") != "") {

			var oldId = parseInt(row.attr("id").replace("row-id-", ""));

			if (oldId != rowId) {
				var event = $.Event("rowIdChanging");
				event.row = row;
				event.oldId = oldId;
				event.newId = rowId;

				console.log("Raising!", event);

				liteGrid.$el.trigger(event);
			}
		}

		//Set the ID based on the data item's ID.
		row.attr("id", "row-id-" + rowId);

		//Bind the actual data item to the row so that we can get it later.
		row.data("dataItem", dataItem);

		$(options.columns).each(function(index) {
			var column = this;

			var value = dataItem[column.field];
			if (value == undefined)
			    value = column.defaultValue;
			if (value == undefined)
			    value = options.missingValue;

			var element = row.children(":eq(" + index + ")");
			element.html(value);

			var event = $.Event("columnBound");
			event.column = column;
			event.element = element;
			event.dataItem = dataItem;

			liteGrid.$el.trigger(event);
		});

		//Raises the "rowBound" event on the table.
		liteGrid.$el.trigger('rowBound', [row, dataItem]);
	}

	//Inserts a row for a data item after the specified row
	//that's already in the table.
	base.insertRowAfter = function(dataItem, existingRow) {

		//Create the row.
		var row = base.buildRow(dataItem);

		//Insert it.
		row.insertAfter(existingRow);

		//The table has been changed, so fire the event.
		liteGrid.$el.trigger("tableUpdated", liteGrid);

		return row;
	}

	//Adds a new row after all other rows.
	base.appendRow = function(dataItem) {

		//Create the row.
		var row = base.buildRow(dataItem);

		//Insert it.
		liteGrid.$el.append(row);

		//The table has been changed, so fire the event.
		liteGrid.$el.trigger("tableUpdated", liteGrid);

		return row;
	}

}